﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using WebApplication1.Entities;
using WebApplication1.EntitiesPersistent.D01DbContext.cs;
using WebApplication1.EntitiesProcess.Tools;

namespace WebApplication1.EntitiesProcess
{
    public class EntityRepository<T> : IEntityRepository<T> where T : class, IEntityBase, new()
    {
        readonly D01DbContext _EntitiesContext;

        public EntityRepository(D01DbContext context)
        {
            _EntitiesContext = context;
        }

        public virtual async Task<bool> SaveAsyn()
        {
            await _EntitiesContext.SaveChangesAsync();
            return true;
        }

        public virtual async Task<IQueryable<T>> GetAllAsyn()
        {
            var dbSet = _EntitiesContext.Set<T>();
            var result = await dbSet.ToListAsync();
            return result.AsQueryable<T>();
        }

        public virtual async Task<IQueryable<T>> GetAllIncludingAsyn(params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> query = _EntitiesContext.Set<T>(); //.Include(includeProperties);
            if (includeProperties != null)
            {
                foreach (var includeProperty in includeProperties)
                {
                    query = query.Include(includeProperty);
                }
            }
            var result = await query.ToListAsync();
            return result.AsQueryable();
        }

        public virtual async Task<T> GetSingleAsyn(Guid id)
        {
            var dbSet = _EntitiesContext.Set<T>();
            var result = await dbSet.FirstOrDefaultAsync(x => x.ID == id);
            return result;
        }

        public virtual async Task<T> GetSingleAsyn(Guid id, params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> dbSet = _EntitiesContext.Set<T>();
            if (includeProperties != null)
            {
                foreach (var includeProperty in includeProperties)
                {
                    dbSet = dbSet.Include(includeProperty);
                }
            }

            var result = await dbSet.FirstOrDefaultAsync(x => x.Id == id);
            return result;
        }

        public virtual async Task<T> GetSingleAsyn(Expression<Func<T, bool>> predicate)
        {
            var dbSet = _EntitiesContext.Set<T>();
            var result = await dbSet.FirstOrDefaultAsync(predicate);
            return result;
        }


        public virtual async Task<IQueryable<T>> FindByAsyn(Expression<Func<T, bool>> predicate)
        {
            var result = await _EntitiesContext.Set<T>().Where(predicate).ToListAsync();
            return result.AsQueryable();
        }

        public virtual async Task<bool> HasInstanceAsyn(Guid id)
        {
            return await _EntitiesContext.Set<T>().AnyAsync(x => x.ID == id);
        }

        public virtual async Task<bool> HasInstanceAsyn(Expression<Func<T, bool>> predicate)
        {
            return await _EntitiesContext.Set<T>().AnyAsync(predicate);
        }

        public virtual async Task<bool> AddOrEditAndSaveAsyn(T entity)
        {
            var dbSet = _EntitiesContext.Set<T>();
            var hasInstance = await dbSet.AnyAsync(x => x.ID == entity.Id);
            if (hasInstance)
                dbSet.Update(entity);
            else
                await dbSet.AddAsync(entity);
            try
            {
                await _EntitiesContext.SaveChangesAsync();
                return true;
            }
            catch (DbUpdateException)
            {
                return false;
            }
        }

        public virtual async Task<DeleteStatusModel> DeleteAndSaveAsyn(Guid id)
        {
            var result = new DeleteStatusModel() { DeleteSatus = true, Message = "删除操作成功！" };
            var hasIstance = await HasInstanceAsyn(id);
            if (!hasIstance)
            {
                result.DeleteSatus = false;
                result.Message = "不存在所指定的数据，无法执行删除操作！";
            }
            else
            {
                var tobeDeleteItem = await GetSingleAsyn(id);
                try
                {
                    _EntitiesContext.Set<T>().Remove(tobeDeleteItem);
                    _EntitiesContext.SaveChanges();
                }
                catch (DbUpdateException ex)
                {
                    result.DeleteSatus = false;
                    result.Message = ex.Message;
                }
            }
            return result;
        }

        public virtual async Task<PaginatedList<T>> PaginateAsyn<TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> keySelector)
        {
            var result = await PaginateAsyn(pageIndex, pageSize, keySelector, null);
            return result;
        }

        public virtual async Task<PaginatedList<T>> PaginateAsyn<TKey>(
            int pageIndex,
            int pageSize,
            Expression<Func<T, TKey>> keySelector,
            Expression<Func<T, bool>> predicate,
            params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> query = await GetAllIncludingAsyn(includeProperties);
            query = query.OrderBy(keySelector);
            query = (predicate == null) ? query : query.Where(predicate);
            return query.ToPaginatedList(pageIndex, pageSize);
        }
    }
}
